package nl.justobjects.pushlet.client;

import nl.justobjects.pushlet.util.PushletException;

import java.util.ArrayList;

public class PushletClientConnectionFactory {
	
	PushletClient pushletClient;
	
	private String masterURL; // 主URL
	private String[] urls;
	private int urlIdx = 0;
    private int tryTimes = 0;
	public String getUrl() {
		return masterURL;
	}
	public void setUrl(String url) {
		if (url.startsWith("failover")) {
			int startPos = url.indexOf("(");
			int endPos = url.indexOf(")");
			if (startPos == -1 || endPos == -1)
				throw new IllegalArgumentException("Wrong url format, it should be 'failover:(url1,url2,...)'.");
			String urlsString = url.substring(startPos + 1, endPos);
			this.urls = urlsString.split(",");
			if (this.urls.length == 0)
				throw new IllegalArgumentException("URL of Pushlet Server is not asigned.");
			this.masterURL = urls[urlIdx];
		} else {
			this.masterURL = url;
            this.urls = new String[] {url};
		}
	}
	
	private String pid;
	public String getPid() {
		return pid;
	}
	public void setPid(String pid) {
		this.pid = pid;
	}
	
	private PushletClientListenerContainer pushletClientListenerContainer;
	public void setPushletClientListenerContainer(PushletClientListenerContainer pushletClientListenerContainer) {
		this.pushletClientListenerContainer = pushletClientListenerContainer;
	}
	
	public PushletClientConnectionFactory() {

	}
	
	public PushletClientConnectionFactory(String url, String pid) {
		this.setUrl(url);
		this.setPid(pid);
	}

	public PushletClient getConnection() throws PushletException {
		this.connect();
		return pushletClient;
	}
	
	public void connect() throws PushletException {
		if (this.pushletClient == null) {
			// 首次建立连接
			pushletClient = new PushletClient(masterURL);
			pushletClient.setDebug(true);
			try {
				pushletClient.join(pid);
				pushletClient.listen(pushletClientListenerContainer);
			} catch (PushletException e) {
				pushletClient.p("[PushletClientConnectionFactory]" + masterURL + " can not establish connection correctly.");
			}
			// 检查连接是否正常
			connect();
		} else {
			int pushletClientStatus = pushletClient.getState();
			if (pushletClientStatus == PushletClient.STATE_LISTENING) {
				// 连接正常，立即返回
				return;
			} else if (pushletClientStatus < PushletClient.STATE_LISTENING) {
				// 连接异常，使用备用地址尝试重新连接
                if (pushletClientStatus == PushletClient.STATE_JOINED) {
                    pushletClient.leave();
                }
                // 使用备用地址重建连接
                masterURL = this.getSlaveURL();
                pushletClient.p("[PushletClientConnectionFactory]Incorrect pushclient status, try to reconnect with slave url - " + masterURL);
                ArrayList<String[]> subscribedSubjects = pushletClient.getSubjects();
                pushletClient = new PushletClient(masterURL);
                // 会话订阅信息
                pushletClient.setSubjects(subscribedSubjects);
                pushletClient.setDebug(true);
                pushletClient.reconnect(pid, pushletClientListenerContainer);
                // 再次检查
                connect();
			}
		}
	}
	
	private String getSlaveURL() throws PushletException {
		// 尝试过所有链接地址，未能正确建立连接则抛出异常
        if (tryTimes == urls.length) {
            tryTimes = 0;
            throw new PushletException("All urls have been tried, no one can establish connection.");
        }
		urlIdx = (urlIdx == (urls.length - 1)) ? 0 : (urlIdx + 1);
        tryTimes++;
        return urls[urlIdx];
	}
}